﻿using Abp.Application.Services.Dto;
using Abp.Domain.Repositories;
using Abp.EntityFrameworkCore.Repositories;
using Abp.Extensions;
using Abp.Linq.Extensions;
using Abp.Organizations;
using Abp.UI;
using ARchGL.Platform.Authorization.Users;
using ARchGL.Platform.Electrocar.Application.Dto;
using ARchGL.Platform.Electrocar.Application.InputDtos;
using ARchGL.Platform.Electrocar.Core;
using ARchGL.Platform.Utils;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace ARchGL.Platform.Electrocar.Application
{
    /// <summary>
    /// 项目服务 实现
    /// </summary>
    public class ProjectsAppService : BaseService
    {
        private readonly IRepository<ProjectUsers, Guid> projectUsersRepository;
        private readonly IRepository<OrganizationUnit, long> organizationUnitRepository;
        private readonly IRepository<Projects, Guid> projectsRepository;
        private readonly IRepository<CarBodys, Guid> carBodysRepository;
        private readonly IRepository<ModelAssemblys, Guid> modelAssemblysRepository;
        private readonly IRepository<ModelDirectorys, Guid> modelDirectorysRepository;
        private readonly IRepository<ModelPropertys, Guid> modelPropertysRepository;

        private readonly UserManager userManager;

        public ProjectsAppService(
            IRepository<Projects, Guid> _carModelsRepository, IRepository<CarBodys, Guid> _carBodysRepository,
            IRepository<ProjectUsers, Guid> _projectUsersRepository,
            IRepository<OrganizationUnit, long> _organizationUnitRepository,
            IRepository<ModelAssemblys, Guid> _modelAssemblysRepository,
            IRepository<ModelDirectorys, Guid> _modelDirectorysRepository, IRepository<ModelPropertys, Guid> _modelPropertysRepository,
            UserManager _userManager, InstallAppService _installAppService)
        {
            projectUsersRepository = _projectUsersRepository;
            organizationUnitRepository = _organizationUnitRepository;
            projectsRepository = _carModelsRepository;
            carBodysRepository = _carBodysRepository;
            modelAssemblysRepository = _modelAssemblysRepository;
            modelDirectorysRepository = _modelDirectorysRepository;
            modelPropertysRepository = _modelPropertysRepository;
            userManager = _userManager;
        }

        /// <summary>
        /// 创建/编辑项目
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task CreateOrModifyProject(ProjectsDto input)
        {
            if (input.Id == Guid.Empty)
            {
                var entity = ObjectMapper.Map<Projects>(input);
                //entity.CreationTime = DateTime.Now;
                await projectsRepository.InsertAsync(entity);

                var carbodyList = await new Init().InitCarBodyInfoAsync(entity.Id);

                foreach (var item in carbodyList)
                {
                    await carBodysRepository.InsertAsync(item);
                }
            }
            //只编辑项目信息
            else
            {
                var entity = await projectsRepository.GetAsync(input.Id);
                if (entity == null) throw new UserFriendlyException("项目不存在，请重新输入");
                entity.Name = input.Name;
                entity.Code = input.Code;
                entity.Level = input.Level;
                entity.Structure = input.Structure;
                entity.Category = input.Category;
                entity.Url = input.Url;
                await projectsRepository.UpdateAsync(entity);
            }
        }

        /// <summary>
        /// 初始化模板（默认模板、项目模板、空模板）
        /// </summary>
        /// <param name="input">项目标识</param>
        /// <returns></returns>
        public async Task InitTemplate(InitTemplateInput input)
        {
            //删除原有结构树
            await DeleteTree(input);

            if (Guid.Empty == input.TemplateId)
            {
                #region 使用默认 结构/属性 模板初始化
                var entity = await projectsRepository.GetAsync(input.ProjectId);
                if (entity == null) throw new UserFriendlyException("项目不存在，请重新输入");

                var templateResult = await new Init().CreatePropertys(input.ProjectId);

                foreach (var item in templateResult.Item1)
                {
                    await modelAssemblysRepository.InsertAsync(item);
                }

                foreach (var item in templateResult.Item2)
                {
                    await modelDirectorysRepository.InsertAsync(item);
                }

                foreach (var item in templateResult.Item3)
                {
                    await modelPropertysRepository.InsertAsync(item);
                }
                #endregion
            }
            else if (null == input.TemplateId)
            {
                //空模板
            }
            else
            {
                //使用项目模板初始化
                var rootId = Guid.NewGuid().ToString().Substring(0, 31);
                string.Intern(rootId);
                var parentId = Guid.Empty;

                #region 复制目标项目模板结构

                //获取目标模板一级总成
                var directorysList = await modelDirectorysRepository.GetAllListAsync(x => x.ProjectId == input.TemplateId.Value);
                var modelDirectorys = from ModelDirectorys entity in directorysList where entity.Level == 1 select entity;

                //获取总成属性
                var assbemlysList = modelAssemblysRepository.GetAll().Where(x => x.ProjectId == input.TemplateId.Value).ToList();

                foreach (var item in modelDirectorys)
                {
                    var number = (count++).ToString().PadLeft(5, '0');
                    var assbemlys = from ModelAssemblys entity in assbemlysList where entity.ParentId == item.Id select entity;
                    //复制模板一级总成属性
                    foreach (var assbemly in assbemlys)
                    {
                        var assbemlyNumber = (assbemlyCount++).ToString().PadLeft(5, '0');
                        assbemly.ParentId = Guid.Parse(rootId + number);
                        assbemly.Id = Guid.Parse(rootId + assbemlyNumber);
                        modelAssbemlysTreeList.Add(assbemly);
                    }

                    
                    await Recursion(item.Id, Guid.Parse(rootId + number), rootId, directorysList, modelDirectorysTreeList, assbemlysList);

                    item.Id = Guid.Parse(rootId + number);
                    item.ParentId = Guid.Empty;
                    modelDirectorysTreeList.Add(item);

                    
                }

                foreach (var item in modelDirectorysTreeList)
                {
                    item.ProjectId = input.ProjectId;
                    await modelDirectorysRepository.InsertAsync(item);
                }

                foreach(var item in modelAssbemlysTreeList)
                {
                    item.ProjectId = input.ProjectId;
                    await modelAssemblysRepository.InsertAsync(item);
                }

                //复制目标项目模板属性
                count = 1;
                var propertysList = await modelPropertysRepository.GetAllListAsync(x => x.ProjectId == input.TemplateId.Value);
                var modelPropertysAssembly = from ModelPropertys entity in propertysList where entity.Level == 1 select entity;
                foreach (var item in modelPropertysAssembly)
                {
                    var number = (count++).ToString().PadLeft(5, '0');
                    await Recursion(item.Id, Guid.Parse(rootId + number), rootId, propertysList, modelPropertysTreeList, assbemlysList);
                    item.Id = Guid.Parse(rootId + number);
                    item.ParentId = Guid.Empty;
                    modelPropertysTreeList.Add(item);
                }
                foreach (var item in modelPropertysTreeList)
                {
                    item.ProjectId = input.ProjectId;
                    await modelPropertysRepository.InsertAsync(item);
                }
                #endregion
            }

        }

        List<ModelDirectorys> modelDirectorysTreeList = new List<ModelDirectorys>();
        List<ModelPropertys> modelPropertysTreeList = new List<ModelPropertys>();
        List<ModelAssemblys> modelAssbemlysTreeList = new List<ModelAssemblys>();
        int count = 1;
        int assbemlyCount = 1;

        /// <summary>
        /// 复制模板数据处理函数
        /// </summary>
        /// <param name="id">总成id</param>
        /// <param name="parentId">父级结构id</param>
        /// <param name="rootId"></param>
        /// <param name="dataList">模板数据集合</param>
        /// <param name="treeList">目标数据集合</param>
        /// <param name="modelAssemblysList">总成属性集合</param>
        /// <returns></returns>
        private async Task Recursion<T>(Guid id, Guid parentId, string rootId, List<T> dataList, List<T> treeList, List<ModelAssemblys> modelAssemblysList) where T : KeyValueBase
        {
            var children = from T entity in dataList where entity.ParentId == id select entity;
            if (0 == children.Count())
                return;
            foreach (var child in children)
            {
                var number = (count++).ToString().PadLeft(5, '0');
                //获取其他级别总成属性
                var assbemlys = from ModelAssemblys entity in modelAssemblysList where entity.ParentId == child.Id select entity;
                //复制模板其他总成属性
                foreach (var assbemly in assbemlys)
                {
                    var assbemlyNumber = (assbemlyCount++).ToString().PadLeft(5, '0');
                    assbemly.ParentId = Guid.Parse(rootId + number);
                    assbemly.Id = Guid.Parse(rootId + assbemlyNumber);
                    modelAssbemlysTreeList.Add(assbemly);
                }

                child.ParentId = parentId;
               

                await Recursion(child.Id, Guid.Parse(rootId + number), rootId, dataList, treeList, modelAssemblysList);

                child.Id = Guid.Parse(rootId + number);

                treeList.Add(child);
            }
        }

        /// <summary>
        /// 删除原项目结构属性
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        private async Task DeleteTree(InitTemplateInput input)
        {
            //如果目录已存在则删除原有目录 
            var modelDirectorysTree = await modelDirectorysRepository.GetAllListAsync(x => x.ProjectId == input.ProjectId);
            if (0 != modelDirectorysTree.Count)
            {
                await modelDirectorysRepository.DeleteAsync(x => x.ProjectId == input.ProjectId);
            }

            //如果属性已存在则删除原有属性
            var modelPropertysTree = await modelPropertysRepository.GetAllListAsync(x => x.ProjectId == input.ProjectId);
            if (0 != modelPropertysTree.Count)
            {
                var sql = $"DELETE FROM {GetTableName<ModelPropertys>()} WHERE ProjectId = @ProjectId";
                modelPropertysRepository.GetDbContext().Database.ExecuteSqlCommand(sql, input.ProjectId);
            }

            //如果总成属性已存在则删除原有属性
            var modelAssemblysTree = await modelAssemblysRepository.GetAllListAsync(x => x.ProjectId == input.ProjectId);
            if(0 != modelAssemblysTree.Count)
            {
                await modelAssemblysRepository.DeleteAsync(x => x.ProjectId == input.ProjectId);
            }
        }

        /// <summary>
        /// 删除项目
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task RemoveProject(EntityDto<Guid> input)
        {
            var entity = await projectsRepository.GetAsync(input.Id);
            if (entity == null) throw new UserFriendlyException("项目不存在，请重新输入");
            await projectsRepository.DeleteAsync(entity);
        }

        /// <summary>
        /// 标记为模版
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task MarkAsTemplate(MarkAsTemplateInput input)
        {
            var entity = await projectsRepository.GetAsync(input.Id);
            if (entity == null) throw new UserFriendlyException("项目不存在，请重新输入");
            entity.IsTemplate = input.IsTemplate;
            await projectsRepository.UpdateAsync(entity);
        }

        /// <summary>
        /// 返回所有标记为模版的项目列表
        /// </summary>
        /// <returns></returns>
        public async Task<List<ProjectsTemplateDto>> QueryTemplateList(EntityDto<Guid> input)
        {
            var result = await projectsRepository.GetAllListAsync(x => x.IsTemplate == true && x.Id != input.Id);
            var templateList = ObjectMapper.Map<List<ProjectsTemplateDto>>(result);
            foreach (var item in templateList)
            {
                item.HasValue = modelDirectorysRepository.GetAll().Any(x => x.ProjectId == item.Id);
            }
            return templateList;
        }
        /// <summary>
        /// 获取项目信息
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<ProjectsDto> QueryProjectById(EntityDto<Guid> input)
        {
            var entity = await projectsRepository.GetAsync(input.Id);
            return ObjectMapper.Map<ProjectsDto>(entity);
        }

        /// <summary>
        /// 获取项目-分页数据集合
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<PagedResultDto<ProjectsDto>> QueryProjectPagedList(ProjectsInput input)
        {
            //return await cacheManager.GetCache("QueryCarModelsPagedList").Get("1asdf", async cache =>
            //{

            var query = projectsRepository.GetAll()
                    .WhereIf(userManager.UserId != 1, x => x.CreatorUserId == userManager.UserId)
                    .WhereIf(input.Level != 0, x => x.Level == input.Level)
                    .WhereIf(input.Structure != 0, x => x.Structure == input.Structure)
                    .WhereIf(input.Category != 0, x => x.Category == input.Category)
                    .WhereIf(!input.CompanyName.IsNullOrWhiteSpace(), x => x.CompanyName.Contains(input.CompanyName))
                    .WhereIf(!input.Keywords.IsNullOrWhiteSpace(), x => x.Name.Contains(input.Keywords));

            var result = await query.OrderByDescending(x => x.CreationTime).PageByAsync(input);

            return new PagedResultDto<ProjectsDto>(query.Count(),
                ObjectMapper.Map<List<ProjectsDto>>(result));
            //});
        }

        /// <summary>
        /// 添加用户至项目
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<Guid> AddUserToProject(AddUserToProjectInput input)
        {
            var entity = input.Map<AddUserToProjectInput, ProjectUsers>();

            if (projectUsersRepository.GetAll().Any(x => x.ProjectId == input.ProjectId && x.UserId == input.UserId))
                throw new UserFriendlyException("用户已存在，请重新输入");

            await projectUsersRepository.InsertAsync(entity);
            return entity.Id;
        }

        /// <summary>
        /// 删除项目用户
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task RemoveUserOnProject(EntityDto<Guid> input)
        {
            var entity = await projectUsersRepository.GetAsync(input.Id);
            if (entity == null) throw new UserFriendlyException("用户不存在，请重新输入");
            await projectUsersRepository.DeleteAsync(entity);
        }

        /// <summary>
        /// 获取项目成员列表
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<PagedResultDto<ProjectUsersDto>> QueryProjectUsersPagedList(ProjectUsersInput input)
        {
            var query = projectUsersRepository.GetAll()
                        .WhereIf(input.ProjectId != Guid.Empty, x => x.ProjectId == input.ProjectId).ToList();

            var projectUsersQuery = from projectUser in query
                                    join ou in organizationUnitRepository.GetAll() on projectUser.OrganizationId equals ou.Id into ouJoined
                                    from ou in ouJoined.DefaultIfEmpty()
                                    join um in userManager.Users on projectUser.UserId equals um.Id
                                    select new ProjectUsersDto
                                    {
                                        Id = projectUser.Id,
                                        ProjectId = projectUser.ProjectId,
                                        UserId = um.Id,
                                        Name = um.Name,
                                        UserName = um.UserName,
                                        EmailAddress = um.EmailAddress,
                                        OrganizationUnitId = ou.Id,
                                        OrganizationUnitName = ou.DisplayName,
                                        PhoneNumber = um.PhoneNumber,
                                        Type = projectUser.Type,
                                        CreationTime = projectUser.CreationTime,
                                    };

            var result = await projectUsersQuery.OrderByDescending(x => x.CreationTime).PageByAsync(input);

            return new PagedResultDto<ProjectUsersDto>(query.Count(),
                ObjectMapper.Map<List<ProjectUsersDto>>(result));
        }
    }
}
